package com.snut.viruscheck.tokenUtils.util;

import com.snut.viruscheck.tokenUtils.constant.GlobalConstant;
import lombok.Setter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import java.util.Calendar;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RedisIdempotentUtils {

     //超时时间
     @Setter
     private long timeout  ;
     @Setter
     private String  module = "module1";
     @Setter
     private  RedisTemplate redisTemplate;

    // An highlighted block
    /**
     * 获取特定时间的 毫秒数
     */
    public static Long getMiol() {
        Calendar ca = Calendar.getInstance();
        //失效的时间
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        long fl = ca.getTimeInMillis();
        return fl;
    }
//UUID.randomUUID().toString()

    // 将idempotent存入在redis
    public String getIdempotent() {
//        String time=System.currentTimeMillis();
        String idempotent = GlobalConstant.IDEMPOTENT.concat(":").concat(UUID.randomUUID().toString());
        String  key = module.concat(":").concat(idempotent);
        String value = key;
//        key和value的关系真的搞不清
        timeout= (getMiol() - System.currentTimeMillis())/1000; //获取剩余时间
        System.out.println (timeout);
        //key: idempotent value: idempotent 时间
        this.setString(key, value, timeout);
        return value;
    }
/*
* 每次调用接口前先要生成token存入redis中，然后再从中获取token放入请求头中，当真正调用接口发出post请求的时候，
* 再从请求头解析token和redis中的token校验，过于复杂，
* 不如第一次请求的才生成唯一id的token过期时间是一天，然后其他请求带自身id查询redis发现有token存在，直接提示不能重复提交
*
*
*
* */

    //从redis查询对应的idempotent   防止没来得及删除 只有一个线程操作 其实redis已经可以防止了
    public synchronized boolean findIdempotent(String idempotentKey) {
        String idempotent = (String) this.getString(idempotentKey);
        //不取非的意思要么被被人使用过了 要么没有对应idempotent
//        取非的意思如果存在，则说明被调用过一次，今天无法提交
        if (StringUtils.isEmpty(idempotent)) {
            return false;
        }
        // idempotent 获取成功后 删除对应idempotentMapsidempotent
//        每天第一个请求过来的可以设置新的key=id的token存入redis中，若查到有该token，则其他接口直接都无法调用，
//        直到缓存一天过期后才能调用
//        todolist：设置key=id的token存入redis，每次用自身的id查token
        this.delKey(idempotent);
        //保证每个接口对应的idempotent只能访问一次，保证接口幂等性问题
        return true;
    }

    private void setString(String key, Object data, Long timeout) {

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        if (data instanceof String) {
            String value = (String) data;
            redisTemplate.opsForValue().set(key, value);
        }

        if (timeout != null) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    private Object getString(String key) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return redisTemplate.opsForValue().get(key);
    }

    private void delKey(String key) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.delete(key);
    }

}